home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Dragonsmith 1.1.1 / Documentation / Dragonsmith Manual (text) < prev    next >
Text File  |  1994-01-15  |  84KB  |  2,312 lines

  1. ------------------------------------------------------
  2. Dragonsmith Programmer’s Manual (text format)
  3. ------------------------------------------------------
  4.  
  5.  
  6. version 1.1
  7. Sunday, October 11, 1992
  8. by Paul Hoffman
  9.  
  10. “Dragons do not enter into this story…”
  11.  
  12.  
  13. Send bug reports, comments, and suggestions to:
  14.  
  15. Mail        Paul Hoffman
  16.             302 W. Davis, Apt. 2
  17.             Ann Arbor MI 48103
  18.             U.S.A.
  19.     
  20. Internet    paul.hoffman@umich.edu
  21.             dragonsmith@umich.edu
  22.  
  23. AFS            /afs/umich.edu/user/n/k/nkuitse
  24.  
  25.  
  26.     **************************************************
  27.     * NOTE:                                          *
  28.     *                                                *
  29.     *    This document is a text-only version of the  *
  30.     *    file “Dragonsmith Programmer’s Manual”       *
  31.     *                                                *
  32.     *    The text is all the same, but a few tables   *
  33.     *    and figures are missing from this file       *
  34.     *                                                *
  35.     **************************************************
  36.  
  37. ------------------------------------------------------
  38. CONTENTS
  39. ------------------------------------------------------
  40.  
  41. Introduction
  42.     What is Dragonsmith?
  43.     What is drag-and-drop, and what is it good for?
  44.     How does the Finder know what can be drag-and-dropped where?
  45.     What is a dragon, and why is it called that?
  46.     What can Dragonsmith do, and what can’t it do?
  47.     Can I use Dragonsmith with System 6?
  48.     Why use object-oriented programming (OOP)?
  49.     Where can I find out more about OOP?
  50.     Does Dragonsmith use the THINK Class Library?
  51.     How do I create my own dragon?
  52.     How do I upgrade from Dragonsmith v1.0b2 to v1.1?
  53.     Will I have to rewrite my code when the next release of Dragonsmith comes out?
  54.  
  55. Getting started
  56.     Dragonsmith 1.1 files
  57.     Upgrading from Dragonsmith 1.0b2
  58.     PreDragon
  59.     Creating the project file
  60.     Creating the project resource file
  61.     Writing a subclass of Dragon
  62.     Compiling and debugging your dragon
  63.  
  64. Program flow
  65.  
  66. When something goes wrong…
  67.     Error ‘Can’t open file “PreDragon”’
  68.     Syntax error at the first line
  69.     Link error ‘Undefined: CreateGDragon’
  70.     AEProcessAppleEvent returns error –608 (noOutstandingHLE)
  71.     AEProcessAppleEvent returns error –609 (connectionInvalid)
  72.     Your dragon won’t drop (or it ‘overdrops’)
  73.     Your dragon crashes shortly after an Apple event is handled
  74.  
  75. Notes on Apple events
  76.  
  77. How to…
  78.     Automatic disk and folder opening
  79.     Adding a menu
  80.     Adding a preference setting
  81.  
  82. Dragons ahoy!
  83.  
  84. Dragon instance variables
  85.  
  86. Dragon methods
  87.  
  88. Resources
  89.  
  90.  
  91. ------------------------------------------------------
  92. INTRODUCTION
  93. ------------------------------------------------------
  94.  
  95. What is Dragonsmith?
  96.  
  97. Dragonsmith is an object-oriented framework for developing drag-and-drop
  98. applications under Macintosh System 7. 
  99.  
  100. What is drag-and-drop, and what is it good for?
  101.  
  102. The drag-and-drop feature of the System 7 Finder lets you open files using
  103. an application other than the one that created it.  Here’s a (rather
  104. simplistic) outline of how this works:
  105.     • The user drags a file’s icon onto that of a drag-and-drop application
  106.     • The Finder launches the application (if it wasn’t already running)
  107.     • The Finder sends the application an Apple event telling it to open the
  108. file
  109.     • The application opens the file
  110.  
  111. How does the Finder know what can be drag-and-dropped where?
  112.  
  113. As you drag a file’s icon around the desktop, the Finder hilites an
  114. application icon the pointer passes over only if the application is capable
  115. of opening that type of file.  (The situation is more complicated when you
  116. drag more than one icon at a time.)  The Finder uses the desktop database to
  117. decide which applications can open which types of files; this information in
  118. turn comes from ‘FREF’ resources found in the application files.  Because
  119. the desktop database sometimes gets messed up (and out of a general sense of
  120. caution), applications developed with Dragonsmith do their own checking of
  121. ‘FREF’ resources and file types.
  122.  
  123. What is a dragon, and why is it called that?
  124.  
  125. A dragon is an application that is driven primarily by drag-and-drop — it
  126. doesn’t do much if you double-click on its icon, but drop a few files on it
  127. and watch it go!  Instead of ‘opening’ drag-and-dropped files, dragons
  128. ‘process’ them.  This ‘processing’ can be any type of action — deleting a
  129. file, compiling an index of it, extracting sounds from its resource fork,
  130. etc.  Here’s a list of some dragon-and-drop applications and what they do:
  131.  
  132.     Alias Director 2.7    Creates aliases to files, folders, and disks.
  133.     Alias Finder        Opens the Finder window containing the original file or
  134.                             folder of an alias.
  135.     FileTyper 3.0        Allows one to change the file type, creator, and other
  136.                             attributes of files.
  137.     GroupInfo            Displays the total amount of disk space used by a group
  138.                             of files and folders.
  139.     Paradigma 2.0        Finds and replaces strings in a text file.
  140.     Save a BNDL            Refreshes a file’s BNDL information to update its icons,
  141.                             etc. in the Finder.
  142.     StuffIt Expander™    Expands StuffIt and CompactPro archives and AppleLink
  143.                             packages.
  144.     Text Merger 1.02    Merges several text files into a single file.
  145.  
  146. There is a great deal of variety among these applications (and others like
  147. them).  Some of them will accept drag-and-dropped folders or disks in
  148. addition to files.  Some process files quietly and quit automatically when
  149. they’re done; others stick around to give you the opportunity to change
  150. settings.  Some only run in System 7; others will run in System 6, using the
  151. Standard File routines to choose the files you want to process.  The
  152. important thing is what they all have in common — drag-and-drop ‘batch’
  153. processing of files.
  154.  
  155. Why the name dragon?
  156.  
  157.     • Dragons are drag-and-dropped on (of course).
  158.     • Dragons are distant cousins of UNIX daemons (which, strangely enough, do
  159. their thing in the wings).
  160.     • Dragons have been known to enter (quite uninvited) into the stories of a
  161. certain amateur writer.
  162.  
  163. What can Dragonsmith do, and what can’t it do?
  164.  
  165. Dragonsmith can be used to create any application, but it wouldn’t make
  166. sense to develop one that didn’t feature drag-and-drop prominently.  There
  167. wouldn’t be much point, for example, in using Dragonsmith to make a word
  168. processor — it would be more suited for an application that displays the
  169. total number of words and paragraphs in a group of text files dropped on it.
  170.  
  171. Because most dragons will probably perform simple tasks, Dragonsmith has
  172. been designed with simplicity in mind.  A simple Dragonsmith-produced
  173. application typically requires only about 20–25K of disk space and runs in
  174. 40–50K of memory.  Because of the object-oriented nature of the Dragonsmith
  175. kit, however, advanced features can easily be added to a dragon.
  176.  
  177. On the other hand, dragons developed with Dragonsmith have several more or
  178. less advanced capabilities:
  179.  
  180. Preferences
  181. Automatic resource-based preferences file management is built
  182. into all dragons.  Any dragon that you create can store, alter, and retrieve
  183. any number of preferences.  The user can ask a dragon to use any particular
  184. preferences file that belongs to it by double-clicking on that file in the
  185. Finder.  As long as you’re careful to program defensively, the dragon will
  186. still run normally if a preferences file could not be found or created.
  187.  
  188. Folder searching
  189. You can specify that folders and disks will automatically
  190. be opened recursively to any desired depth in search of files to be
  191. processed.
  192.  
  193. Alias resolution
  194. If folder searching is enabled, then any alias files
  195. encountered may (optionally) be automatically resolved.
  196.  
  197. Safe file handling
  198. A dragon will “see” only those documents (files, folders,
  199. and volumes) that the Finder would allow the user to drag-and-drop on it. 
  200. If the dragon looks inside a folder dropped on it, or if it receives an Open
  201. Documents event from a source other than the Finder, it will ignore any
  202. files it doesn’t know what to do with.
  203.  
  204. Smart file filtering
  205. A dragon can easily be made to process only files that
  206. match specific criteria besides just the file type — name, size, creator,
  207. location, etc.
  208.  
  209. Background processing
  210. A dragon will run quietly in the background if the
  211. user decides to switch to (or launch) another application after dropping
  212. files on it; the dragon will take as much or as little CPU time away from
  213. other applications as you want it to.
  214.  
  215. Apple event queuing
  216. The user can drag-and-drop documents on a dragon (or
  217. another Apple-event-savvy application can send the dragon an Open Documents
  218. event) while the dragon is busy at work on something else — each batch of
  219. documents will be processed in the order in which it was received.
  220.  
  221. Auto-quit
  222. You can specify that a dragon will automatically quit after
  223. processing drag-and-dropped documents (or if double-clicked in the Finder).
  224.  
  225. Environment checking
  226. A dragon will terminate gracefully if launched in a
  227. run-time environment insufficient for its needs — and the specifications for
  228. its run-time requirements can be changed without any source code
  229. modifications.
  230.  
  231.  
  232. The following features are not supported by Dragonsmith 1.1 but are under
  233. consideration for future releases:
  234.  
  235. Apple Event objects
  236. Adding Apple Event Object Model and scripting support is
  237. a high priority.  This will enable control of dragons by Apple event-savvy
  238. applications, including scripting environments like UserLand Frontier and
  239. the forthcoming AppleScript.  A small Dragon suite of custom Apple events is
  240. a possibility.
  241.  
  242. Improved error handing
  243. The Dragon class’s error handling capability is
  244. currently rudimentary.  Improvements will include better reporting of errors
  245. to the user and, when Apple Event Object support is added, to client
  246. applications.
  247.  
  248. Progress window
  249. Also in the works is a movable modal dialog to show what
  250. documents are being processed, display error messages, etc.
  251.  
  252. More sophisticated preferences handling
  253. There is currently no support in the Dragon and Preferences classes for
  254. preferences file ‘Open,’ ‘Save’ and ‘Save As…’ operations.  These
  255. capabilities should form part of a general preferences-editing interface —
  256. perhaps via a ‘Preferences…’ item added to the ‘Edit’ menu.
  257.  
  258. Drakelings
  259. There is a growing trend in the Macintosh world toward
  260. ‘miniature’ custom stand-alone drag-and-drop applications created by a
  261. ‘master’ application — Frontier’s applets belong to this category, as do the
  262. ‘ParaDoids’ created by Espen Aarseth’s excellent Paradigma, and the
  263. ‘AutoTypers’ in Daniel Azuma’s FileTyper package.  Implementing this type of
  264. document-application hybrid in Dragonsmith is a high priority.
  265.  
  266. Faceless dragons
  267. Some dragons don’t need any user interface.  The Dragon
  268. class currently uses an instance variable autoQuit to designate that a
  269. dragon will quit immediately after receiving the first Open Documents event
  270. it receives.  A better solution, however, would be a simpler class (of which
  271. Dragon would become a subclass) designed for creating background-only
  272. dragons.  This could significantly reduce the size of simple faceless
  273. dragons, which is especially important in light of the interface
  274. enhancements planned for the Dragon class.
  275.  
  276. FilterTop support
  277. The freeware FilterTop project currently under development
  278. will provide a programming framework similar in some ways to that of
  279. Dragonsmith. FilterTop is likely to garner a good deal of popularity, and
  280. Dragonsmith and it should be able to complement each other very nicely.
  281.  
  282. Can I use Dragonsmith with System 6?
  283.  
  284. No, System 7 is required.  The whole point of dragons is defeated in a
  285. no-drag-and-drop, no-Apple-events environment.
  286.  
  287. Why use object-oriented programming (OOP)?
  288.  
  289. The center of Dragonsmith’s drag-and-drop framework is provided the Dragon
  290. class.  To write your own dragon, you’ll create a new subclass of Dragon
  291. that ‘inherits’ the bulk of its code.  Using OOP, you can easily override or
  292. extend Dragon’s behavior without altering any source files — you can change
  293. as much or as little as you need to.
  294.  
  295. Where can I find out more about OOP?
  296.  
  297. You might begin by reading parts of the THINK C Object-Oriented Programming
  298. Manual (for THINK C 5.0).  Pages 19–24 and 28–51 are a good starting point,
  299. and pages 81–86 contain some information specific to using OOP in THINK C.
  300.  
  301. Does Dragonsmith use the THINK Class Library?
  302.  
  303. No.  For most drag-and-drop applications, the TCL is overkill — it contains
  304. a vast amount of code that most dragons will never need.
  305.  
  306. On the other hand, you could use the TCL — using code from Dragon.c, write a
  307. subclass of CApplication called CDragonApp or some such.  It shouldn’t be
  308. overwhelmingly difficult.
  309.  
  310. [Remember, the source code in Dragonsmith may be freely altered and used for
  311. any purpose, subject only to the restrictions mentioned at the beginning of
  312. each file.  Applications developed using Dragonsmith may be sold or given
  313. away without restriction.]
  314.  
  315. How do I create my own dragon?
  316.  
  317. The easiest way is to base your dragon on one of the template classes
  318. provided.  Each of these files has step-by-step instructions on how to use
  319. it to write your own dragon:
  320.  
  321.     PlainTmpl.c        A very simple ‘auto-quit’ dragon without any interface
  322.     MenusTmpl.c        A simple dragon with an added menu
  323.     PrefsTmpl.c        A simple dragon with an added menu and preferences settings
  324.  
  325. You might also want to read the source code files for the finished dragons
  326. provided with this release of Dragonsmith — DFileCleaver.c, DFilePaths.c,
  327. and DPasser.c
  328.  
  329. How do I upgrade from Dragonsmith v1.0b2 to v1.1?
  330.  
  331. Follow the instructions in the Getting Started section below.  The basic
  332. steps are:
  333.  
  334.     • Replace the old Dragonsmith.π with the one in this release.  You can
  335. throw away Dragonsmith.debug.π — it’s no longer needed.
  336.  
  337.     • Move the bulk of your ProcessDroppings method to ProcessFile (and
  338. possibly move some to the BeginProcessing and EndProcessing methods) — this
  339. may require adding a few instance variables.  Your dragon will no longer
  340. need to directly access the data in the Open Documents event.
  341.  
  342.     • If your dragon added any menus, rewrite its SetUpMenus and DoMenu methods
  343. and remove its basic Apple, File, and Edit menu functionality — they’re now
  344. implemented in Dragon.
  345.  
  346.     • Change your dragon’s signature from ‘Drgn’ to some other unique value, if
  347. you hadn’t already.
  348.  
  349.     • Add some resources to your project’s resource file.
  350.  
  351.     • Recompile all the files in your project.
  352.  
  353. Will I have to rewrite my code when the next release of Dragonsmith comes
  354. out?
  355.  
  356. Hopefully not.  This manual will warn you about certain features of the
  357. Dragon class that, for future compatibility, are best left alone.  Still,
  358. the most important thing is to get the most out of the functionality already
  359. in the Dragon class — future incompatibility dangers shouldn’t inhibit you
  360. more than a little.
  361.  
  362.  
  363. ------------------------------------------------------
  364. GETTING STARTED
  365. ------------------------------------------------------
  366.  
  367. Dragonsmith 1.1 files
  368.  
  369. Dragonsmith
  370.     ! Read me
  371.     Base files  <Normally, you shouldn’t add to this folder or alter the files
  372.             in it — if you use a copy of one of these files, move it up into
  373.             the Dragonsmith folder>
  374.         Classes
  375.             AppleEventQueue.c
  376.             AppleEventQueue.h
  377.             Preferences.c  <A resource-based preferences management class that
  378.                 may be used outside of Dragonsmith>
  379.             Preferences.h
  380.         DFileCleaver.c
  381.         DFilePaths.c
  382.         DPasser.c
  383.         Dragon.c  <Code for the Dragon class>
  384.         Dragon.h
  385.         Dragonsmith TMPLs  <ResEdit templates for editing custom resource types used
  386. in Dragonsmith>
  387.         Dragonsmith.π    <Use a copy of this project file with your code added for
  388. greater debugging control than is provided by (a copy of) Template.π>
  389.         FileCleaver.π
  390.         FileCleaver.π.rsrc
  391.         FilePaths.π
  392.         FilePaths.π.rsrc
  393.         Main.c  <Contains the function main used for all dragons>
  394.         Passer.π
  395.         Passer.π.rsrc
  396.         PreDragon.c  <Source for the PreDragon precompiled headers file used by
  397. Dragonsmith projects>
  398.         Utilities  <Source code containing various utility functions>
  399.             [numerous files]
  400.     Documentation
  401.         ! Release notes
  402.         Dragonsmith Programmer’s Manual
  403.         Dragonsmith Manual (text)  <This file>
  404.         Preferences class notes
  405.     Dragons
  406.         ! Read Me (Dragons)
  407.         File Cleaver 1.1
  408.         File Paths 1.1  <Used to produce this list of files>
  409.         Passer 1.1  <A dragon that passes Open Documents events to high level
  410. event-aware processes — vital for debugging Apple event-handling code in the
  411. THINK C Debugger>
  412.     Template files  <Source code and resource template files for three simple
  413. kinds of Dragon subclass>
  414.         DMenusTmpl.c
  415.         DPlainTmpl.c
  416.         DPrefsTmpl.c
  417.         MenusTmpl.π.rsrc
  418.         PlainTmpl.π.rsrc
  419.         PrefsTmpl.π.rsrc
  420.     Template.π  <Project file to copy and use with the template files>
  421.  
  422. Upgrading from Dragonsmith 1.0b2
  423.  
  424. The original release of Dragonsmith was much more simplistic.  Processing of
  425. documents was treated as a single step — the dragon developer was required
  426. to write (in ProcessDroppings) a loop to extract, then process, each
  427. document from the Open Documents Event.  Any desired filtering of documents
  428. (treating files and folders differently, resolving alias files, opening only
  429. files of a certain type, etc.) had to be done by the subclass of Dragon. 
  430. Programmers who needed file information were responsible for calling
  431. PBGetCatInfo themselves.  In Dragonsmith 1.1, most of this ‘grunt’ work is
  432. done for you by the Dragon class.
  433.  
  434. The changes in functionality have brought about several significant changes
  435. in the Dragon class iinterface, and all Dragon 1.0b2 subclasses will have to
  436. be modified to work with Dragon 1.1.
  437.  
  438. ProcessDroppings
  439.  
  440. In Dragonsmith 1.0b2, every Dragon subclass had to override
  441. ProcessDroppings.  In version 1.1, that’s no longer true.  In general,
  442. ProcessFile (and possibly ProcessDirectory) should be overridden;
  443. ProcessDroppings should not.
  444.  
  445. To update your dragon to Dragonsmith 1.1, you’ll probably move most of the
  446. code from your ProcessDroppings method to ProcessFile — though some of it
  447. may need to go into BeginProcessing and EndProcessing.  Updating your dragon
  448. will probably also require changing a few local variables in your old
  449. ProcessDroppings method to instance variables.
  450.  
  451. In addition, ProcessDroppings’ parameters have changed.  The docs parameter
  452. isn’t needed any more because information about the current file or
  453. directory is always accessible in *curDocFSS (an FSSpec record) and
  454. *curDocPB (a multi-purpose parameter block subsuming the HParamBlockRec,
  455. CInfoPBRec, and other low-level File Manager param-blocks).  The numDocs
  456. parameter has no counterpart in Dragon 1.1 — a more sophisticated file
  457. counting and tracking mechanism is planned for a future version of
  458. Dragonsmith.
  459.  
  460. Menus
  461.  
  462. The new Dragon class implements standard Apple and Edit menus, plus a File
  463. menu with a single Quit item.  The DFilePaths class released as part of
  464. Dragonsmith 1.0b2 used a different means to implement essentially the same
  465. menus — any dragons modeled after it will need to be changed to adhere to
  466. Dragon 1.1’s menu scheme.  Look at the DMenusTmpl.c file for an example of
  467. how a dragon should add menus.
  468.  
  469. Signatures and the Desktop Manager
  470.  
  471. Dragonsmith 1.0b2 didn’t make it clear that every new dragon should have a
  472. unique application signature (and, for clarity, a distinct icon in the
  473. Finder).  If more than one application in your Mac work environment has the
  474. same signature, then drag-and-drop for either of them (or both) may not work
  475. properly.  You are encouraged to assign your dragons unique signatures and
  476. register each one with Apple.
  477.  
  478. PreDragon
  479.  
  480. One of the first things you should do is to make a precompiled headers file
  481. from PreDragon.c.  The resulting file should be named PreDragon and placed
  482. in the Base Files folder.  The source files in the Dragonsmith kit all rely
  483. on these precompiled headers.
  484.  
  485. Creating the project file
  486.  
  487. Start with a copy of Template.π (or a copy of Dragonsmith.π if you want more
  488. control over debugging), then add the file which holds the source code for
  489. your dragon.  The code for a simple dragon will most likely fit into a
  490. single segment, not counting extra segments (such as ‘CODE’ 0) that THINK C
  491. creates transparently.
  492.  
  493. Make sure you choose ‘Set Project Type…’ from THINK C’s Project menus and
  494. set the appropriate values for Creator (signature), partition, and SIZE
  495. flags.
  496.  
  497. Creating the project resource file
  498.  
  499. In general, you should start with a copy of one of the …Tmpl.π.rsrc files
  500. and make modifications as necessary.  The first changes you make should be
  501. in ‘STR ’ 128, the ‘FREF’ resources, and ‘DrPr’ 128.  The Resources section
  502. in this document and the source files in the ‘Template Files’ folder contain
  503. descriptions of the various resources used by Dragonsmith, as well as
  504. information on which resources to change and how.
  505.  
  506. Writing a subclass of Dragon
  507.  
  508. It’s recommended that you start with one of the template classes provided in
  509. the ‘Template Files’ folder.  Information on how to make a dragon this way
  510. is provided in the source files.  If you had previously developed a dragon
  511. using Dragonsmith 1.0b2, you should read the section Upgrading from
  512. Dragonsmith 1.0b2 above.  For tips on adding specific functionality to your
  513. dragon, refer to the section How To… below.
  514.  
  515. Constructor method
  516.  
  517. Your dragon should use a constructor (a method with no return-value, whose
  518. name is that of the class to which it belongs) to initialize any instance
  519. variables it adds.  Your dragon’s constructor will be executed (immediately
  520. after the Dragon class’s constructor) when the gDragon object is made in
  521. CreateGDragon.  It should set any default instance variable values that you
  522. want to be different from the values assigned in Dragon::Dragon.  If your
  523. dragon implements any custom preferences resources, you should add instance
  524. variables to hold their values and your constructor should set defaults for
  525. them (in case the ReadPrefs method fails).
  526.  
  527. ProcessFile and ProcessDirectory
  528.  
  529. These are the two most important methods — without overriding one or both of
  530. them, your dragon won’t do anything.  If your dragon makes simple changes to
  531. a file or directory’s catalog information, it can use the macros described
  532. below (curFileType, curDocCreated, etc.) to change the appropriate fields in
  533. curDocPB, then (at the end of ProcessFile or ProcessDirectory) call the
  534. SaveDocInfo method to have the information changed on disk.  For more
  535. information, see Macros below and read the notes for SaveDocInfo in the
  536. Methods section.
  537.  
  538. CreateGDragon
  539.  
  540. This function is not defined in Dragon.c — the code for it must be found in
  541. one of your dragon’s source files.  It performs the very important task of
  542. creating a dragon object of the desired Dragon subclass, and can be written
  543. as simply as this:
  544.  
  545. Dragon *CreateGDragon (void)
  546. {
  547.     return (Dragon *) new DMyDragonClass;
  548. }
  549.  
  550. Compiling and debugging your dragon
  551.  
  552. Passer
  553.  
  554. Drag-and-drop is at the heart of dragons, so you’ll need a way to debug your
  555. dragon’s ProcessFile method (and related code).  Unfortunately, there’s no
  556. way to drag-and-drop files onto your dragon while it’s running in the
  557. THINK C Debugger.  Instead, you’ll have to use the ‘Passer’ dragon provided
  558. with Dragonsmith 1.1 to transmit Open Documents events to your dragon while
  559. it’s being debugged.  To do so, choose ‘Run’ from the Project menu in
  560. THINK C, then start up Passer and choose ‘Target…’ from its Options menu. 
  561. Once you’ve selected your dragon’s process from the resulting PPCBrowser
  562. dialog, any Open Documents events sent to Passer will simply be rerouted to
  563. your dragon without modification.  Set a breakpoint in ProcessFile (or
  564. ProcessDirectory) to ‘catch’ the event, then debug from there.
  565.  
  566. Apple events and the THINK C Debugger
  567.  
  568. While running your dragon in the THINK C Debugger, you must be careful not
  569. to set any breakpoints in code executed between a call to WaitNextEvent that
  570. returns a high-level event and the call to AEProcessAppleEvent that
  571. dispatches the event to the appropriate Apple event handler.  You can set
  572. breakpoints in the handler itself and in the Dragon method it calls.  If you
  573. forget this and set a breakpoint in the wrong place, AEProcessAppleEvent
  574. will return a noOutstandingHLE (–608) error and the event will not be
  575. dispatched.  Presumably this is due to a time-out internal to the Apple
  576. Event Maneger package (‘PACK’ 8), because it seems to happen whether the
  577. source of the event specifies a time-out value or not.
  578.  
  579. If you want to send yourself an Apple event, use the kCurrentProcess
  580. constant instead of sending by signature — your signature under the THINK C
  581. Debugger is ‘KAHL’ and THINK C or the THINK C Debugger may intercept the
  582. event.
  583.  
  584. Don’t set any breakpoints between a call to WaitNextEvent that returns a
  585. high-level event and the ensuing call to AEProcessAppleEvent.  Otherwise,
  586. the Apple event will time out and AEProcessAppleEvent will return –608
  587. (noOutstandingHLE).  This may also be true of AcceptHighLevelEvent — it
  588. hasn’t been tested.
  589.  
  590.  
  591.  
  592. ------------------------------------------------------
  593. PROGRAM FLOW
  594. ------------------------------------------------------
  595.  
  596. Figure 1 shows the flow of execution of a dragon as it starts up and
  597. subsequently receives an Open Documents event:
  598.  
  599.     <Figure 1 omitted>
  600.  
  601. The main event loop in Dragon is essentially the same as that in almost any
  602. Macintosh application.  For each event returned by WaitNextEvent, the
  603. DoEvent method calls the appropriate event-handling method — DoMouseDown,
  604. DoSuspend, DoResume, DoKeyDown, etc.  When an Open Documents event is
  605. received by your dragon, DoEvent calls DoHighLevelEvent, which dispatches
  606. the event to HandleOdoc, the Open Documents handler installed in the
  607. InitAppleEvents method.  HandleOdoc in turn sends a DoOdoc message to
  608. gDragon, the global dragon object.  DoOdoc extracts the event’s
  609. keyDirectObject parameter (the list of documents to open) and uses it as a
  610. parameter to ProcessDroppings, which calls ProcessDoc for each document in
  611. the list.
  612.  
  613. Things can get considerably more complicated than this diagram shows:
  614.  
  615.     • When dirDepthLimit < 0 and ProcessDoc encounters a directory,
  616. ProcessDocsInDirectory will be executed instead of ProcessFile or
  617. ProcessDirectory, and recursion back to ProcessDoc will probably occur.
  618.  
  619.     • The ProcessOwnedFile method will be called instead if your dragon is
  620. asked to open a file that belongs to it (i.e., one whose creator code is
  621. your dragon’s signature).  Typically, this is a preferences file, but a
  622. Dragon subclass might use this feature for other things — to implement
  623. script files, for example.
  624.  
  625.     • If a document your dragon is asked to open is of a type that it doesn’t
  626. ‘know about’ (i.e., that is not covered by its ‘FREF’ resources), or if the
  627. document is rejected by CustomFilterDoc, then ProcessDoc will not be
  628. executed.
  629.  
  630.     • If the dragon is busy processing something when an Open Documents event
  631. is received, DoOdoc will call SuspendAEvent instead of ProcessDroppings. 
  632. This will add the event to a queue for later processing — the event will be
  633. ‘on hold’ until all preceding ‘odoc’ events have been processed.  The next
  634. time WaitNextEvent fails to return an event, Run will call ResumeAEvent to
  635. complete handling of the event.  This way, all Open Documents events will be
  636. processed in the order in which they were received.  Note that when a Quit
  637. Application event is received, any suspended events will return an error to
  638. the sending process and will not result in any documents being processed.
  639.  
  640.  
  641. ------------------------------------------------------
  642. WHEN SOMETHING GOES WRONG…
  643. ------------------------------------------------------
  644.  
  645. Error ‘Can’t open file “PreDragon”’
  646.  
  647. Either you haven’t created the PreDragon precompiled headers file from
  648. PreDragon.c, or it’s located where THINK C can’t find it.  See Creating your
  649. dragon skeleton above for more information.
  650.  
  651. Syntax error at the first line
  652.  
  653. The problem may be with your project prefix — it should end with the line
  654.  
  655.     #include "PreDragon"
  656.  
  657. Choose ‘Options…’ from THINK C’s Edit menu to bring up a dialog where you
  658. can set this.  You should not #include <MacHeaders> in the project prefix.
  659.  
  660. Link error ‘Undefined: CreateGDragon’
  661.  
  662. You’ve forgotten to define (write the code for) the CreateGDragon function. 
  663. It should create an instance of your Dragon subclass (not of Dragon) and
  664. return a reference to the object, like this:
  665.  
  666. Dragon *CreateGDragon (void)
  667. {
  668.     return (Dragon *) new DMyDragonClass;
  669. }
  670.  
  671. AEProcessAppleEvent returns error –608 (noOutstandingHLE)
  672.  
  673. You may have set a breakpoint between the WaitNextEvent call that obtained
  674. the event and the AEProcessAppleEvent call that dispatched to your handler —
  675. see Compiling and debugging your dragon above for more information on using
  676. the THINK C Debugger.
  677.  
  678. It is safe to set a breakpoint in your Apple event handler, or in the code
  679. that it calls (DoOapp, DoOdoc, DoPdoc, or DoQuit).
  680.  
  681. AEProcessAppleEvent returns error –609 (connectionInvalid)
  682.  
  683. You may have forgotten to set the ‘high level event aware’ flag in your
  684. project’s ‘SIZE’ resource.  Both the sender and receiver of a high-level
  685. event must have this flag set.
  686.  
  687. Your dragon won’t drop (or it ‘overdrops’)
  688.  
  689. If this is the first time you’ve built your dragon, check to make sure that
  690. you’ve given it a unique signature and not ‘????’ (or ‘Drgn’ — Dragonsmith
  691. v1.0b2 implied that you should use this value).
  692.  
  693. If you’ve built it before, then there may be a problem with the desktop
  694. database.  Delete any obsolete versions of your dragon that accepted
  695. different types (or move them to a floppy disk) and rebuild the desktop. 
  696. (The utility application ‘Save a BNDL’ may let you avoid this step — but use
  697. it with caution.)
  698.  
  699. Your dragon crashes shortly after an Apple event is handled
  700.  
  701. Your Apple event may be returning an invalid error code.  Make sure it
  702. returns an error listed in Inside Macintosh VI.  It’s not clear why this
  703. would cause a bus error, but it seemed to do so in an early version of
  704. Dragonsmith.
  705.  
  706.  
  707. ------------------------------------------------------
  708. NOTES ON APPLE EVENTS
  709. ------------------------------------------------------
  710.  
  711. Any application which is high level event aware will receive exactly one of
  712. the three following kinds of events when launched by the Finder:
  713.  
  714. Open Application
  715. If this event is received, the user double-clicked on the
  716. application in the Finder, or selected the application and chose ‘Open’ from
  717. the File menu.
  718.  
  719. Open Documents
  720. If this event is received, the user double-clicked on a file
  721. (or group of files) belonging to the application, or selected the file(s)
  722. and chose ‘Open’ from the File menu, or drag-and-dropped it (or them) onto
  723. the application’s icon.
  724.  
  725. Print Documents
  726. If this event is received, the user selected a file (or
  727. group of files) and chose ‘Print’ from the File menu.
  728.  
  729. An application may receive any number of Open Documents and Print Documents
  730. from the Finder after it has started.
  731.  
  732. Other processes may launch an application with any kind of Apple event, or
  733. none at all, and may later send any kind and number of Apple events to it. 
  734. Because of this, your code should never rely on receiving any Apple events
  735. in any sequence.
  736.  
  737. QuitApplication
  738. The Finder will send a Quit Application event to an
  739. application if the user chooses ‘Restart’ or ‘Shut Down’ from the ‘Special’
  740. menu (and possibly under other circumstances as well).  Other processes may
  741. send this event to the application at any time.
  742.  
  743.  
  744. ------------------------------------------------------
  745. HOW TO…
  746. ------------------------------------------------------
  747.  
  748. Automatic disk and folder opening
  749.  
  750. To make your dragon automatically process files inside directories (i.e.,
  751. volumes and folders), change the value of dirDepthLimit (in your constructor
  752. as well as in the ‘DrPr’ 128 resource) to a negative number indicating how
  753. many levels down your dragon will look.  This feature can be very handy, but
  754. it can also be very dangerous.  To avoid stack overflow, you should not set
  755. dirDepthLimit to a value less than about -100.  If you set resolveAliases =
  756. TRUE, then the possibility of recursion becomes an issue.
  757.  
  758. Figure 2 shows a hierarchical view of the contents of a folder
  759. ‘Miscellaneous’ — the depth of each file or folder (except 0 Another File
  760. alias) is indicated by the number its name begins with.  How your dragon
  761. should set its instance variables (and the corresponding values in its
  762. ‘DrPr’ 129 resource) depends on what action you want it to take when the
  763. user drag-and-drops the hilited files on it.  (For the sake of this example,
  764. it’s assumed that your dragon has ‘FREF’ resources for types ‘fold’ and
  765. ‘TEXT’ and that all the files pictured are text files.)
  766.  
  767.     <Figure 2 omitted>
  768.  
  769. Table 1 gives details on which combinations of values will result in a
  770. particular set of documents being processed.  In several cases, the value of
  771. one or two instance variables is irrelevant.
  772.  
  773.     <Table 1 omitted>
  774.  
  775. Adding a menu
  776.  
  777. Refer to the file ‘MenusTmpl.c’ for a simple illustration of how to add
  778. menus to your dragon.  The information below on adding a preferences setting
  779. also shows how to add a menu.
  780.  
  781. Adding a preference setting
  782.  
  783. The ‘PrefsTmpl.c’ file contains sample code showing you how to implement
  784. preferences in Dragonsmith.  By default, every dragon will use a preferences
  785. file, whether it needs it or not — to prevent your dragon from finding or
  786. creating a preferences file, put a null string in the ‘STR ’ 128 resource
  787. and remove the ‘FREF’ resource for the type designated by the instance
  788. variable prefsFileType.
  789.  
  790. The ‘PrRo’ 128 resource in your dragon’s preferences (and application) file
  791. contains references to the preferences resources which belong to it.  The
  792. first resource designated in the ‘PrRo’ 128 resource must be ‘DrPr’ 128,
  793. which contains several important values used by every Dragon subclass (see
  794. below).
  795.  
  796. Documentation for the Preferences class is minimal in this release of
  797. Dragonsmith — a later release will correct that.  In the mean time, reading
  798. the source code for the class may be instructive.
  799.  
  800. The steps involved in adding a new preference to your dragon are as follows:
  801.  
  802.     • Add a resource in your project resource file to hold the preferences
  803. value(s)
  804.  
  805.     • Create an entry for the added preferences resource at the end of the
  806. ‘PrRo’ 128 resource in your project resource file
  807.  
  808.     • Add an instance variable to hold a handle to the added resource
  809.  
  810.     • Add instance variables to your Dragon subclass to hold the values from
  811. your added resource
  812.  
  813.     • In your dragon’s constructor method, initialize the preferences instance
  814. variables to safe, if-all-else-fails default values — your dragon should not
  815. crash or abort if some preferences couldn’t be found
  816.  
  817.     • Override ReadPrefs as indicated below
  818.  
  819.     • Add some way in your dragon’s interface to change the additional
  820. preference(s)
  821.  
  822.     • Add code to change the preferences resource in memory and save it to disk
  823.  
  824. As an example, take the case of a dragon (named ‘Scruncher’) that uses one
  825. of three compression methods (Fast, Normal, or Tight) to compact files.  The
  826. user can choose any one of the three, and may also specify whether Finder
  827. information about the file is preserved in the resulting archive.  These
  828. preferences are stored in a ‘ScPr’ 128 resource in the Scruncher.π.rsrc
  829. file.  Figure 3 shows the dragon’s added menu:
  830.  
  831.     <Figure 3 omitted>
  832.  
  833. The DScruncher.c file would look something like this:
  834.  
  835. #include    "Dragon.h"
  836. #include    “MenuUtils.h”
  837. #include    “Preferences.h”
  838. #define    prefScruncherPrefs    prefDragonPrefs + 1
  839. enum {
  840.     mOptions = mEdit + 1
  841. };
  842. enum {
  843.     iFastScrunching,
  844.     iNormalScrunching,
  845.     iSmallScrunching,
  846.     iLine3,
  847.     iSaveFInfo
  848. };
  849.     
  850. typedef struct {
  851.     char        scrunchType;
  852.     Boolean    saveFInfo;
  853. } ScrunchOpts;
  854.  
  855. class DScruncher : public Dragon {
  856.  
  857.     protected:
  858.         ScrunchOpts    **scrunchOptions;
  859.         char        scrunchType;
  860.         Boolean        saveFInfo;
  861.         
  862.     public:
  863.                     DScruncher (void);    // Constructor
  864.                     
  865.     protected:
  866.         [Protected method declarations omitted for brevity]
  867. };
  868.  
  869. Dragon *CreateGDragon (void)
  870. {
  871.     return (Dragon *) new DScruncher;
  872. }
  873.  
  874. DScruncher::DScruncher (void)
  875. {
  876.     optionsMenu = NULL;
  877.     scrunchOptions = NULL;
  878.     scrunchType = iNormalScrunching;
  879.     saveFInfo = TRUE;
  880. }
  881.  
  882. void DScruncher::ReadPrefs (void)
  883. {
  884.     inherited::ReadPrefs ();
  885.  
  886.     scrunchOptions = (ScrunchOpts **) preferences->GetPrefResource
  887.             (prefFilePathOptions);
  888.  
  889.     if (scrunchOptions != NULL) {
  890.         HNoPurge ((Handle) scrunchOptions);
  891.         scrunchType = scrunchOptions->scrunchType;
  892.         saveFInfo = scrunchOptions->saveFInfo;
  893.     }
  894. }
  895.  
  896. void DScruncher::SetUpMenus (void)
  897. {
  898.     inherited::SetUpMenus ();        // Add the Apple, File, and Edit menus
  899.  
  900.     optionsMenu = GetMenu (mOptions);
  901.     InitOptionsMenu ();
  902.     InsertMenu (optionsMenu, 0);
  903.  
  904.     DrawMenuBar ();
  905. }
  906.  
  907. void DScruncher::InitOptionsMenu (void)
  908. {
  909.     // Initialize options menu (and set the options while we’re at it)
  910.     CheckItem (optionsMenu, iSaveFInfo, saveFInfo);
  911.     SetScrunchType (iFastScrunching + scrunchType - 1);
  912. }
  913.  
  914. void DScruncher::DoMenu (long menuItemCode)
  915. {
  916.     if (menuItemCode >> 16 == mOptions)
  917.         DoOptionsMenu (menuItemCode & 0xFFFF);
  918.     else
  919.         inherited::DoMenu (menuItemCode);
  920. }
  921.  
  922. void DScruncher::DoOptionsMenu (short itemNum)
  923. {
  924.     if (itemNum == iSaveFInfo)
  925.         ToggleSaveFInfo ();
  926.     else
  927.         SetScrunchType (itemNum);
  928.  
  929.     // Save any changes that might have been made
  930.     preferences->SavePrefResource (prefFilePathOptions);
  931. }
  932.  
  933. void DScruncher::ToggleSaveFInfo (void)
  934. {
  935.     saveFInfo = ToggleMenuItem (optionsMenu, iSaveFInfo);
  936.     if (scrunchOptions)
  937.         (*scrunchOptions)->saveFInfo = saveFInfo;
  938. }
  939.  
  940. void DScruncher::SetScrunchType (short scrunchItem)
  941. {
  942.     CheckOne (optionsMenu, iFastScrunching, iSmallScrunching, scrunchItem);
  943.     scrunchType = scrunchItem;
  944.     if (scrunchOptions)
  945.         (*scrunchOptions)->scrunchType = scrunchType;
  946. }
  947.  
  948. void DFilePaths::AdjustMenusBusy (void)
  949. {
  950.     inherited::AdjustMenusBusy ();
  951.     DisableItem (optionsMenu, 0);        // Disable the Options menu
  952. }
  953.  
  954. void DFilePaths::AdjustMenusIdle (void)
  955. {
  956.     inherited::AdjustMenusIdle ();
  957.     EnableItem (optionsMenu, 0);        // Enable the options menu
  958. }
  959.  
  960.  
  961. ------------------------------------------------------
  962. DRAGONS AHOY!
  963. ------------------------------------------------------
  964.  
  965. Here’s a list of some dragons that have been spotted by the author on the
  966. (albeit distant) horizon:
  967.  
  968. Drawk
  969. ‘Load’ an awk program, then drag-and-drop input files.
  970.  
  971. D. D. Rex
  972. Specify text substitutions using grep syntax, then drag-and-drop
  973. files to make the changes in — something like Paradigma, but with grep
  974. capability.
  975.  
  976. Proto Drake
  977. Make function and method prototype files from drag-and-dropped C
  978. source files.
  979.  
  980. Icon Elephant
  981. Tired of the Finder spontaneously rearranging your windows’
  982. icons under mysterious circumstances, after you spent five minutes getting
  983. the icons just right?  Drag-and-drop a folder on Icon Elephant to restore
  984. ‘remembered’ icon positions on demand.
  985.  
  986. Dragon Deity
  987. Create Dragonsmith source code and related files quickly and
  988. easily; check projects and their resource files for consistency,
  989. completeness, and general good health.
  990.  
  991. THINK C Thief
  992. Drag-and-drop THINK C 5.0 projects to discover what files they
  993. contain, and more.
  994.  
  995.  
  996. ------------------------------------------------------
  997. DRAGON INSTANCE VARIABLES
  998. ------------------------------------------------------
  999.  
  1000. Most of the instance variables described below should normally not be
  1001. altered by subclasses of Dragon.  Instance variables whose values are set in
  1002. ReadPrefs (from the ‘DrPr’ 128 resource) are noted.
  1003.  
  1004. abortProcessing
  1005.  
  1006. Boolean abortProcessing;
  1007.  
  1008. Don’t change the value of this instance variable directly — call
  1009. StopProcessing instead
  1010.  
  1011. This flag will be set to TRUE if a serious error prevents the current Open
  1012. Documents from continuing, or if the user cancels processing by pressing
  1013. Command–period.
  1014.  
  1015. acceptableTypes
  1016.  
  1017. TypeListHndl acceptableTypes;
  1018.  
  1019. Don’t change the value of this instance variable or the data it points to
  1020.  
  1021. This is a handle to a list of document types (taken from your dragon’s
  1022. ‘FREF’ resources) that your dragon knows how to process.
  1023.  
  1024. aeQueue
  1025.  
  1026. AppleEventQueue *aeQueue;
  1027.  
  1028. Don’t change the value of this instance variable
  1029.  
  1030. This is a reference to an instance of class AppleEventQueue, which is used
  1031. to manage a simple FIFO queue of Open Documents events received while your
  1032. dragon is processing documents from a previous event.
  1033.  
  1034. appFile
  1035.  
  1036. FSSpec appFile;
  1037.  
  1038. Don’t change the value of this instance variable
  1039.  
  1040. This contains an FSSpec to your application — it’s set in the Dragon class’s
  1041. constructor and can be used in any way you want.
  1042.  
  1043. appleMenu
  1044.  
  1045. MenuHandle appleMenu;
  1046.  
  1047. Don’t change the value of this instance variable
  1048.  
  1049. This is a handle to the standard Apple menu implemented by the Dragon class.
  1050.  
  1051. appResFork
  1052.  
  1053. short appResFork;
  1054.  
  1055. Don’t change the value of this instance variable
  1056.  
  1057. This instance variable contains a refNum to the resource fork of your dragon
  1058. — it’s the access path created by the system when the application is
  1059. launched.
  1060.  
  1061. Note:    When running in the THINK C Debugger, appResFork is actually a refNum
  1062. to the project resource file.  The effect in either case is identical.
  1063.  
  1064. autoQuit
  1065.  
  1066. Boolean autoQuit;
  1067.  
  1068. Will be set in ReadPrefs
  1069.  
  1070. This instance variable determines whether your dragon will terminate after
  1071. processing the first Apple event it receives — DoOapp, DoOdoc, and DoPdoc
  1072. all test the value in autoQuit.  Also, because an auto-quit dragon won’t
  1073. have any use for menus, the Start method will call SetUpMenus only if
  1074. autoQuit != FALSE.
  1075.  
  1076. busyCursor
  1077.  
  1078. CursHandle busyCursor;
  1079.  
  1080. This is a handle to the watch cursor (not animated) that is displayed (by
  1081. CursorBusy) when your dragon is processing documents in the foreground.
  1082.  
  1083. Note:    Cursor animation is planned for a later release of Dragonsmith.
  1084.  
  1085. curDirDepth
  1086.  
  1087. short curDirDepth;
  1088.  
  1089. Don’t change the value of this instance variable
  1090.  
  1091. The depth at which your dragon is currently processing documents.  A depth
  1092. of 0 indicates that the current document was specified in an Open Documents
  1093. event your dragon received.  A depth of -1 indicates that the current
  1094. document is located immediately inside a folder or disk specified in an Open
  1095. Documents event.
  1096.  
  1097. curDocFSS
  1098.  
  1099. FSSpec *curDocFSS;
  1100.  
  1101. Don’t change the value of this instance variable; you can change the data to
  1102. which it points
  1103.  
  1104. Pointer to an FSSpec designating the current document.  The data in
  1105. *curDocFSS is meaningful only while your dragon is processing documents.
  1106.  
  1107. curDocPB
  1108.  
  1109. PBRecUnion *curDocPB;
  1110.  
  1111. Don’t change the value of this instance variable; you can change the data to
  1112. which it points
  1113.  
  1114. This is a pointer to a PBRecUnion designating the current document.  A
  1115. PBRecUnion is a union of the six parameter blocks used in making low-level
  1116. File Manager calls.  The data in *curDocPB is meaningful only while your
  1117. dragon is processing documents.  Your dragon is free to change, in the
  1118. ProcessFile and ProcessDirectory methods, any of the data to which curDocPB
  1119. points.  If it does so, it can call SaveDocInfo to make the changes
  1120. permanent and (optionally) refresh the Finder’s display of the window
  1121. containing the document in order to make the changes visible to the user.
  1122.  
  1123. If you’re unfamiliar with the low-level File Manager routines and their
  1124. various parameter blocks, you can safely ignore curDocPB altogether — or you
  1125. can use the macros defined in Dragon.h and described in the section Macros
  1126. to access fields in curDocPB without having to understand how the macros
  1127. work.
  1128.  
  1129. Warning:    Use of these macros can be tricky.  Make sure that you understand
  1130. when it is and is not safe to use them.
  1131.  
  1132. cursorRgn
  1133.  
  1134. RgnHandle cursorRgn;
  1135.  
  1136. This instance variable is used as a parameter to WaitNextEvent.  The Dragon
  1137. class sets it to NULL.  Your dragon should allocate a region in cursorRgn if
  1138. it uses mouse-moved events.
  1139.  
  1140. dirDepthLimit
  1141.  
  1142. short dirDepthLimit;
  1143.  
  1144. Will be set in ReadPrefs
  1145.  
  1146. The depth (a negative value) to which your dragon will look inside nested
  1147. directories in search of documents to process.  The depth of each of the
  1148. documents drag-and-dropped on your dragon is 0, so if dirDepthLimit is 0,
  1149. then your dragon will only see the documents specified in the Open Documents
  1150. event.
  1151.  
  1152. Warning:    Recursive (but not infinitely recursive) directory scanning may
  1153. occur if dirDepthLimit < 0 and resolveAliases == TRUE.  For more
  1154. information, read the section Automatic disk and folder opening above.  Even
  1155. if resolveAliases == FALSE, because of the danger of stack overflow your
  1156. dragon should not set dirDepthLimit lower than about –50.  (Every recursion
  1157. of ProcessDocsInDirectory requires 70 bytes on the stack, so this would
  1158. consume 3500 bytes.)
  1159.  
  1160. dragonPrefs
  1161.  
  1162. DragonPrefsRec **dragonPrefs;
  1163.  
  1164. Don’t change the value of this instance variable
  1165.  
  1166. The values in dragonPrefs are read from the ‘DrPr’ 128 resource (in
  1167. ReadPrefs) and are used to set the following instance variables:
  1168.  
  1169. filesOnly    sleepValue[0..3]
  1170.  
  1171. resolveAliases    sleepTime
  1172.  
  1173. followAliasChain    dirDepthLimit
  1174.  
  1175. autoQuit
  1176.  
  1177. editMenu
  1178.  
  1179. MenuHandle editMenu;
  1180.  
  1181. Don’t change the value of this instance variable
  1182.  
  1183. This is a handle to the standard Edit menu implemented by the Dragon class.
  1184.  
  1185. fileMenu
  1186.  
  1187. MenuHandle fileMenu;
  1188.  
  1189. Don’t change the value of this instance variable
  1190.  
  1191. This is a handle to the minimal File menu (containing a single Quit item)
  1192. implemented by the Dragon class.
  1193.  
  1194. filesOnly
  1195.  
  1196. Boolean filesOnly;
  1197.  
  1198. Will be set in ReadPrefs
  1199.  
  1200. The value of filesOnly is tested only when all of the following are true:
  1201.  
  1202.     • Your dragon has an ‘FREF’ resource for the document type ‘fold’ or ‘disk’
  1203.  
  1204.     • Your dragon encounters a directory at the maximum depth (curDirDepth ==
  1205. dirDepthLimit)
  1206.  
  1207.     • useCustomFilter == FALSE or the directory passes the CustomFilterDoc test
  1208.  
  1209. Under these circumstances, ProcessDirectory will be executed only if
  1210. filesOnly is FALSE.  This instance variable should be set to TRUE if you
  1211. want to ensure that ProcessDirectory will never be called.  See the How to…
  1212. section for more information on what combination of values to use to achieve
  1213. a particular drag-and-drop effect.
  1214.  
  1215. Note:    It doesn’t make sense to add ‘FREF’ resources for ‘disk’ and ‘fold’
  1216. types, then set dirDepthLimit to 0 and filesOnly to TRUE.
  1217.  
  1218. followAliasChain
  1219.  
  1220. Boolean followAliasChain;
  1221.  
  1222. Will be set in ReadPrefs
  1223.  
  1224. This instance variable is only meaningful if resolveAliases == TRUE. 
  1225. Normally, followAliasChain should be TRUE — if not, then an alias file at
  1226. the beginning of an alias chain will only be resolved one step of the way
  1227. rather than all the way to the original document.
  1228.  
  1229. menusInstalled
  1230.  
  1231. Boolean menusInstalled;
  1232.  
  1233. Don’t change the value of this instance variable
  1234.  
  1235. This instance variable will be set to TRUE as soon as your dragon’s menus
  1236. have been installed.  Several Dragon methods rely on the value of
  1237. menusInstalled to avoid a crash.
  1238.  
  1239. numAEsPending
  1240.  
  1241. short numAEsPending;
  1242.  
  1243. Don’t change the value of this instance variable
  1244.  
  1245. This is the number of outstanding Apple events tracked by the aeQueue
  1246. object.
  1247.  
  1248. preferences
  1249.  
  1250. Preferences *preferences;
  1251.  
  1252. Don’t change the value of this instance variable
  1253.  
  1254. This is a reference to an instance of class Preferences, used to manage the
  1255. dragon’s preferences.
  1256.  
  1257. Note:    If you don’t want your dragon to use a preferences file, you should
  1258. not alter (or delete) this object — set the ‘STR ’ 128 resource to "\p"
  1259. instead (and delete the ‘FREF’ for type prefsFileType).  The preferences
  1260. object is used to manage preferences, not just a preferences file.
  1261.  
  1262. prefsFileType
  1263.  
  1264. OSType prefsFileType;
  1265.  
  1266. This is the file type of your dragon’s preferences file.  The System 7
  1267. Finder supplies a generic icon for files of type ‘pref’, and that’s the
  1268. value that Dragon uses.
  1269.  
  1270. resolveAliases
  1271.  
  1272. Boolean resolveAliases;
  1273.  
  1274. Will be set in ReadPrefs
  1275.  
  1276. The value of this instance variable determines whether your dragon will
  1277. automatically resolve alias files that it encounters while processing
  1278. documents from an ‘odoc’ event.  Normally, alias files will only be found
  1279. inside a drag-and-dropped directory, when dirDepthLimit < 0 — the Finder
  1280. automatically resolves alias files before putting them in the event’s list
  1281. of documents.  An Open Documents event sent by any other application,
  1282. however, may contain references to alias files.
  1283.  
  1284. Warning:    You should not set resolveAliases = TRUE (in your dragon’s
  1285. constructor or in its ‘DrPr’ 128 resource) unless either of these two
  1286. conditions is true:
  1287.  
  1288.     • Nothing ‘bad’ will happen if your dragon processes the same file more
  1289. than once.
  1290.  
  1291.     • Your dragon can tell if it’s already processed a file.
  1292.  
  1293. One way to make sure you don’t process the same file twice would be to call
  1294. TickCount in your dragon’s BeginProcessing method, keep the result in an
  1295. instance variable, and store this value in a resource (say, ‘PTix’ 128) in
  1296. every file that’s processed.  Then a simple check (in CustomFilterDoc,
  1297. probably) of this resource for each file your dragon gets will ensure that
  1298. nothing gets processed twice.  The only problem with this approach is that
  1299. would slow things down considerably.
  1300.  
  1301. Even if your dragon does not set resolveAliases = TRUE, there’s no guarantee
  1302. that it won’t process the same file twice — the user might well
  1303. drag-and-drop a file and an alias to the same file simultaneously.  You
  1304. shouldn’t worry too much about this possibility, since there’s very little
  1305. you can do about it.
  1306.  
  1307. running
  1308.  
  1309. Boolean running;
  1310.  
  1311. Don’t change the value of this instance variable directly — call StopRunning
  1312. instead
  1313.  
  1314. This flag is TRUE as long as your dragon is running.  It will be set to
  1315. FALSE in StopRunning to cause your dragon to quit (by ‘falling’ out of the
  1316. main event loop in Run).
  1317.  
  1318. runState
  1319.  
  1320. short runState;
  1321.  
  1322. Don’t change the value of this instance variable
  1323.  
  1324. The low two bits of this instance variable designate the current state of
  1325. your dragon.  The following masks can be used to read these flags:
  1326.  
  1327. maskInBG    0x0001    Indicates the dragon is running in the background 
  1328.  
  1329. maskBusy     0x0002    Indicates the dragon is processing documents
  1330.  
  1331. This instance variable is maintained for your dragon by the Dragon class’s
  1332. constructor and its BeginProcessing, EndProcessing, DoSuspend, and DoResume
  1333. methods.
  1334.  
  1335. signature
  1336.  
  1337. OSType signature;
  1338.  
  1339. Don’t change the value of this instance variable
  1340.  
  1341. This is your dragon’s application signature.  You should assign unique
  1342. signatures to the dragons you create and register each with Apple.
  1343.  
  1344. sleepTime
  1345.  
  1346. long sleepTime;
  1347.  
  1348. This instance variable is used as a parameter to WaitNextEvent to indicate
  1349. the maximum number of ticks your dragon will relinquish to other processes. 
  1350. Its value is maintained by the Dragon class’s constructor and its
  1351. BeginProcessing, EndProcessing, DoSuspend, DoResume, and ReadPrefs methods.
  1352.  
  1353. sleepValue[4]
  1354.  
  1355. long sleepValue[4];
  1356.  
  1357. Will be set in ReadPrefs
  1358.  
  1359. The four values in this instance variable denote the possible values for
  1360. sleepTime when indexed by the low two bits of runState.
  1361.  
  1362. useCustomFilter
  1363.  
  1364. Boolean useCustomFilter;
  1365.  
  1366. Set useCustomFilter to TRUE if your dragon’s CustomFilterDoc method is used
  1367. to filter out unwanted documents.
  1368.  
  1369.  
  1370. ------------------------------------------------------
  1371. DRAGON METHODS
  1372. ------------------------------------------------------
  1373.  
  1374. Each method description is preceded by its declaration (from the body of the
  1375. Dragon class declaration in Dragon.h).  Many of the methods have
  1376. restrictions on how a subclass should or should not override them.  ‘Do not
  1377. override’ should not be taken as an absolute; it simply means that you
  1378. should have a thorough understanding of what the method does in Dragon (and
  1379. why) before you override it.  There are a few more explicit warnings as well
  1380. — these should be taken a bit more seriously.
  1381.  
  1382. Abort
  1383.  
  1384. virtual void Abort (short errNum);
  1385.  
  1386. Abort is called whenever a serious error occurs that prevents execution of
  1387. the dragon application from continuing.  This method displays an error alert
  1388. terminates the program.
  1389.  
  1390. Warning:    Your dragon should be very careful about calling Abort — in
  1391. general, you should avoid calling it any time after the Start method has
  1392. completed execution.
  1393.  
  1394. AdjustMenusBusy
  1395.  
  1396. virtual void AdjustMenusBusy (void);
  1397.  
  1398. Call inherited::AdjustMenusBusy if you override this method
  1399.  
  1400. This method disables any menu items that the user must not be able to select
  1401. while the dragon is processing documents — notably, Quit.  It does not
  1402. disable the Apple menu.  If your dragon has any additional menus (or menu
  1403. items), you should override this method to avoid leaving any dangerous items
  1404. enabled while the dragon is “busy.”
  1405.  
  1406. AdjustMenusIdle
  1407.  
  1408. virtual void AdjustMenusIdle (void);
  1409.  
  1410. Call inherited::AdjustMenusIdle if you override this method
  1411.  
  1412. This method is the converse of AdjustMenusBusy — it restores any menu items
  1413. that were disabled when the dragon began processing documents.
  1414.  
  1415. BeginProcessing
  1416.  
  1417. virtual void BeginProcessing (void);
  1418.  
  1419. Call inherited::BeginProcessing if you override this method
  1420.  
  1421. BeginProcessing is called by ProcessDroppings before any drag-and-dropped
  1422. documents are processed.  Its default behavior in Dragon is to disable any
  1423. menu items that must not be called while processing is going on, then put up
  1424. a “busy” cursor.
  1425.  
  1426. CallMoreMasters
  1427.  
  1428. virtual void CallMoreMasters (void);
  1429.  
  1430. CallMoreMasters calls MoreMasters the number of times specified in the
  1431. ‘MoMa’ 128 resource (as described below) in order to allocate additional
  1432. master pointers.  The resource files provided in the folder ‘Template Files’
  1433. all contain a value of 0 in the ‘MoMa’ 128 resource.
  1434.  
  1435. CanProcessDoc
  1436.  
  1437. virtual Boolean CanProcessDoc (void);
  1438.  
  1439. Don’t override
  1440.  
  1441. CanProcessDoc checks to make sure that the file or directory specified in
  1442. curDocFSS and curDocPB is of a type that could be drag-and-dropped on your
  1443. dragon and applies any special filtering you’ve specified with
  1444. useCustomFilter and CustomFilterDoc.
  1445.  
  1446. CursorBusy
  1447.  
  1448. virtual void CursorBusy (void);
  1449.  
  1450. This method changes the cursor to a watch (not animated) to show that the
  1451. application is doing something.
  1452.  
  1453. Note:    Cursor animation is planned for a later release of Dragonsmith.
  1454.  
  1455. CursorIdle
  1456.  
  1457. virtual void CursorIdle (void);
  1458.  
  1459. This method changes the cursor to show that the application is idle.
  1460.  
  1461. CustomFilterDoc
  1462.  
  1463. virtual Boolean CustomFilterDoc (void);
  1464.  
  1465. Override if your dragon needs to perform any additional filtering of
  1466. documents beyond that provided by the Dragon class
  1467.  
  1468. The CustomFilterDoc method will be called by ProcessDoc if and only if
  1469. useCustomFilter != FALSE.  For example, if your dragon reads a C source file
  1470. and produces a header file with prototypes for the functions and methods
  1471. contained in it, then your CustomFilterDoc method will presumably filter out
  1472. any file whose type is not ‘TEXT’ or whose name doesn’t end with “.c”.
  1473.  
  1474. Note:    Your CustomFilterDoc method can go ahead and call one of a number of
  1475. different document-handling methods, based on whatever criteria it chooses,
  1476. and then return FALSE to fool ProcessDoc into thinking that the document
  1477. shouldn’t be processed at all.  If your dragon does this, however, you
  1478. should keep in mind that future versions of Dragonsmith may provide an
  1479. else-clause in ProcessDoc that takes some action if (it believes that) a
  1480. document could not be handled.
  1481.  
  1482. DoAbout
  1483.  
  1484. virtual void DoAbout (void);
  1485.  
  1486. Override this method if you want your dragon to display a splash window.
  1487.  
  1488. This method is executed when the user chooses the ‘About…’ item from the
  1489. Apple menu.  The default in the Dragon class is to do nothing.
  1490.  
  1491. DoActivate
  1492.  
  1493. virtual void DoActivate (EventRecord *theEvent);
  1494.  
  1495. Override this method if your dragon has windows
  1496.  
  1497. This method is called by DoEvent whenever an activate event occurs (when a
  1498. window is being activated, not deactivated).  Refer to Inside Macintosh
  1499. Volume VI, pages 5–14 to 5–17 for a description of the ‘SIZE’ resource’s
  1500. effect on activate events.
  1501.  
  1502. DoAppleMenu
  1503.  
  1504. virtual void DoAppleMenu (short itemNum);
  1505.  
  1506. Do not override
  1507.  
  1508. DoAppleMenu is called whenever the user chooses an item in the Apple menu.
  1509.  
  1510. DoBusy
  1511.  
  1512. virtual void DoBusy (void);
  1513.  
  1514. You shouldn’t have to override this method (since you can override
  1515. ShowProgress instead); call inherited::DoBusy if you do
  1516.  
  1517. This method is the “busy” counterpart of DoIdle — it’s called when your
  1518. dragon is processing docs rather than when it has nothing to do.  The Dragon
  1519. class calls it (at the beginning of ProcessDoc) for each document to be
  1520. processed; your dragon can make additional calls to DoBusy in order to yield
  1521. CPU time to other processes and to let the user switch to another
  1522. application or cancel the document processing.  The Dragon class’s DoBusy
  1523. method calls ShowProgress and WaitNextEvent (in that order).
  1524.  
  1525. Warning:    Your dragon should not call DoBusy at any time when cancellation by
  1526. the user, or a Quit Application event sent by another process, would cause
  1527. problems.  (It’s up to you to determine what ‘problems’ means…)
  1528.  
  1529. DoDeactivate
  1530.  
  1531. virtual void DoActivate (EventRecord *theEvent);
  1532.  
  1533. Override this method if your dragon has windows
  1534.  
  1535. This method is called by DoEvent whenever an activate event occurs (when a
  1536. window is being deactivated, not activated).  Refer to Inside Macintosh
  1537. Volume VI, pages 5–14 to 5–17 for a description of the ‘SIZE’ resource’s
  1538. effect on activate events.
  1539.  
  1540. DoDiskInsert
  1541.  
  1542. virtual void DoDiskInsert (EventRecord *theEvent);
  1543.  
  1544. Do not override
  1545.  
  1546. This method is called by DoEvent whenever a disk insert event occurs. 
  1547. Dragon::DoDiskInsert handles the event in the usual way, calling DIBadMount
  1548. to give the user a chance to initialize the disk if it’s damaged or not yet
  1549. initialized.
  1550.  
  1551. DoEditMenu
  1552.  
  1553. virtual void DoEditMenu (short itemNum);
  1554.  
  1555. Override this method if you add any items to your dragon’s File menu.  Call
  1556. inherited::DoEditMenu if the item chosen isn’t one of the added items.
  1557.  
  1558. This method is executed whenever the user selects an item in the Edit menu. 
  1559. Dragon::DoEditMenu implements the standard behavior of an Edit menu with
  1560. Undo, Cut, Copy, Paste, and Clear items (plus a dividing line between Undo
  1561. and Cut).
  1562.  
  1563. DoEvent
  1564.  
  1565. virtual void DoEvent (EventRecord *event);
  1566.  
  1567. Do not override
  1568.  
  1569. This is the main “switchboard” from which event handling is dispatched. 
  1570. Your dragon would have to override this method only if it wanted to treat
  1571. keyDown and autoKey events differently.
  1572.  
  1573. DoFileMenu
  1574.  
  1575. virtual void DoFileMenu (short itemNum);
  1576.  
  1577. Override this method if you add any items to your dragon’s File menu.  Call
  1578. inherited::DoFileMenu if the item chosen isn’t one of the added items.
  1579.  
  1580. This method is executed whenever the user selects an item in the File menu. 
  1581. The default behavior in Dragon::DoFileMenu simply checks to see if the item
  1582. chosen is the last item in the menu, and calls StopRunning if it is.
  1583.  
  1584. Warning:    If your File menu doesn’t end with Quit, then you should override
  1585. this method and not call inherited::DoFileMenu.
  1586.  
  1587. DoHighLevelEvent
  1588.  
  1589. virtual void DoHighLevelEvent (EventRecord *theEvent);
  1590.  
  1591. Do not override
  1592.  
  1593. This method is called by DoEvent whenever a high level event occurs.  It
  1594. calls AEProcessAppleEvent if it’s an Apple event, or DoOtherHLEvent if it’s
  1595. not.
  1596.  
  1597. DoIdle
  1598.  
  1599. virtual void DoIdle (void);
  1600.  
  1601. Override this method if your dragon does some periodic task(s) while nothing
  1602. else is happening.
  1603.  
  1604. DoIdle is called by Run each time WaitNextEvent returns no event (or a null
  1605. event).  It’s the “idle” counterpart of DoBusy, described above.
  1606.  
  1607. Note:    When overriding this method, keep in mind that your DoIdle will be
  1608. called only when your dragon is not processing any documents and no
  1609. already-received Apple events are waiting to be processed.  Your method can
  1610. rely on these facts to make assumptions about the dragon’s state.
  1611.  
  1612. DoKeyDown
  1613.  
  1614. virtual void DoKeyDown (EventRecord *theEvent);
  1615.  
  1616. Call inherited::DoKeyDown if you override this method and your method
  1617. doesn’t handle the event
  1618.  
  1619. This method is called by DoEvent whenever a keyDown or autoKey event occurs.
  1620.  It checks for command–key combinations (those in the menus as well as
  1621. –period).
  1622.  
  1623. DoMenu
  1624.  
  1625. virtual void DoMenu (long menuItemCode);
  1626.  
  1627. Override this method if you add any menus to your dragon.  Call
  1628. inherited::DoMenu if the item chosen isn’t in one of the added menus.
  1629.  
  1630. DoMenu is called in response to a mouseDown in the menu bar or command-key
  1631. menu equivalent.  
  1632.  
  1633. DoMouseDown
  1634.  
  1635. virtual void DoMouseDown (EventRecord *theEvent);
  1636.  
  1637. Override this method if your dragon has windows
  1638.  
  1639. This method is called by DoEvent whenever a mouseDown event occurs.
  1640.  
  1641. DoMouseUp
  1642.  
  1643. virtual void DoMouseUp (EventRecord *theEvent);
  1644.  
  1645. This method is called by DoEvent whenever a mouseUp event occurs.  You may
  1646. need to override this method if you override DoMouseDown.
  1647.  
  1648. DoOapp
  1649.  
  1650. virtual OSErr DoOapp (AppleEvent *theAppleEvent, AppleEvent *theReply,
  1651. long refcon);
  1652.  
  1653. This method is called when the user launches the dragon from the Finder by a
  1654. means other than drag-and-drop (i.e., by double-click, select and open, or
  1655. select and Cmd–Down Arrow).  The default DoOapp method in Dragon just checks
  1656. to see if autoQuit == TRUE and calls StopRunning if it is.
  1657.  
  1658. DoOdoc
  1659.  
  1660. virtual OSErr DoOdoc (AppleEvent *theAppleEvent, AppleEvent *theReply,
  1661. long refcon);
  1662.  
  1663. DoOdoc is called by the Apple event handler function HandleOdoc whenever the
  1664. dragon receives an Open Documents (‘odoc’) event.  If the dragon is already
  1665. processing an Apple event, it calls SuspendAEvent and returns.  Otherwise,
  1666. it gives the list of documents in the keyDirectObject parameter of the Open
  1667. Documents event to ProcessDropping.  Finally, it checks to see if autoQuit
  1668. == TRUE and calls StopRunning if it is.
  1669.  
  1670. DoOSEvent
  1671.  
  1672. virtual void DoOSEvent (EventRecord *theEvent);
  1673.  
  1674. Override this method if your dragon handles mouse-moved events or maintains
  1675. its own private scrap
  1676.  
  1677. This method is called by DoEvent whenever an OS event occurs.  It in turn
  1678. calls DoSuspend or Doresume.
  1679.  
  1680. DoOtherHLEvent
  1681.  
  1682. virtual void DoOtherHLEvent (EventRecord *theEvent);
  1683.  
  1684. Override this method if your dragon handles non-Apple event high level
  1685. events
  1686.  
  1687. This method is called by DoHighLevelEvent whenever a high level event that
  1688. is not an Apple event occurs.
  1689.  
  1690. DoPdoc
  1691.  
  1692. virtual OSErr DoPdoc (AppleEvent *theAppleEvent, AppleEvent *theReply,
  1693. long refcon);
  1694.  
  1695. DoPdoc will be called if the user (in the Finder) selects a file that
  1696. belongs to your dragon and chooses “Print” from the File menu.  Very few
  1697. dragons will need to override this method — the default Dragon::DoPdoc
  1698. merely returns an error.  Like DoOapp and DoOdoc, it checks to see if
  1699. autoQuit == TRUE and calls StopRunning if it is.
  1700.  
  1701. DoQuit
  1702.  
  1703. virtual OSErr DoQuit (AppleEvent *theAppleEvent, AppleEvent *theReply,
  1704. long refcon);
  1705.  
  1706. DoQuit calls StopRunning, which will set running = FALSE to terminate the
  1707. main event loop.
  1708.  
  1709. DoResume
  1710.  
  1711. virtual void DoResume (void);
  1712.  
  1713. Override this method if your dragon needs to perform any additional actions
  1714. when it moves to the background.
  1715.  
  1716. DoResume is called whenever your dragon receives a resume event. 
  1717. Dragon::DoResume adjusts the values of runState and sleepTime and, if the
  1718. dragon is busy processing documents, calls CursorBusy to show a busy cursor.
  1719.  
  1720. DoSuspend
  1721.  
  1722. virtual void DoSuspend (void);
  1723.  
  1724. Override this method and call inherited::DoSuspend if your dragon needs to
  1725. perform any additional actions when it moves to the background.
  1726.  
  1727. DoSuspend is called whenever your dragon receives a suspend event. 
  1728. Dragon::DoSuspend adjusts the values of runState and sleepTime and, if the
  1729. dragon is busy processing documents, calls CursorIdle to restore the
  1730. standard arrow cursor.
  1731.  
  1732. DoUpdateEvent
  1733.  
  1734. virtual void DoUpdateEvent (EventRecord *theEvent);
  1735.  
  1736. Override this method if your dragon has windows
  1737.  
  1738. This method is called by DoEvent whenever an update event occurs.
  1739.  
  1740. Dragon
  1741.  
  1742. Dragon (void);
  1743.  
  1744. This is the Dragon constructor, which is called when the gDragon object is
  1745. created (in main), before the constructor (if there is one) for your
  1746. subclass of Dragon.
  1747.  
  1748. EndProcessing
  1749.  
  1750. virtual void EndProcessing (void);
  1751.  
  1752. Call inherited::EndProcessing if you override this method
  1753.  
  1754. This method performs “housekeeping” tasks associated with the completion of
  1755. document processing — it sets sleepTime to the appropriate value and calls
  1756. AdjustMenusIdle and CursorIdle.
  1757.  
  1758. Error
  1759.  
  1760. virtual void Error (short errNum);
  1761.  
  1762. The Error method displays a very simple alert showing a brief message and
  1763. the number passed in the errNum parameter.
  1764.  
  1765. FindPrefsFile
  1766.  
  1767. virtual Boolean FindPrefsFile (FSSpec *fss);
  1768.  
  1769. Do not override
  1770.  
  1771. This method looks for your dragon’s preferences file (the name of which is
  1772. specified in your dragon’s ‘STR ‘ 128 resource).  It looks first in the same
  1773. folder that contains your dragon, then in the Preferences folder within the
  1774. System folder.  If necessary, it calls MakePrefsFile to create a new file.
  1775.  
  1776. Finish
  1777.  
  1778. virtual void Finish (void);
  1779.  
  1780. Call inherited::Finish if you override this method
  1781.  
  1782. Finish is called by main after the Run method has ended.  It’s responsible
  1783. for any last-minute “clean-up” — close any open files, delete temporary
  1784. files, remove trap patches, dispose of objects, etc.  The default behavior
  1785. in Dragon is to dispose of the preferences object, flush the Apple events
  1786. queue (returning errors in the reply events of any pending Apple events),
  1787. and dispose of the aeQueue object.
  1788.  
  1789. Warning:    If you override Finish, you must call inherited::Finish at the end
  1790. of your method.  If the code in Dragon::Finish is not executed, the current
  1791. preferences will not be saved and there is a possibility (of unknown
  1792. likelihood) that a crash will occur if there are any pending Apple events.
  1793.  
  1794. FlushAEventQueue
  1795.  
  1796. virtual void FlushAEventQueue (void);
  1797.  
  1798. Do not override
  1799.  
  1800. FlushAEventQueue is called by Finish when there any pending Apple events. 
  1801. It asks the aeQueue object for each of the pending Apple events, then calls
  1802. AEResumeTheCurrentEvent with a pointer to the ReturnEventNotHandled
  1803. function.  This tells the sender of each pending Apple event that the event
  1804. wasn’t handled — since Finish is the last code that is executed, there’s no
  1805. possibility of handling any events at this point.
  1806.  
  1807. InitAppleEvents
  1808.  
  1809. virtual void InitAppleEvents (void);
  1810.  
  1811. Override this method if your dragon handles any additional Apple events
  1812.  
  1813. InitAppleEvents installs handlers for the four required Apple events, and
  1814. calls MakeAEQObject.
  1815.  
  1816. InitMac
  1817.  
  1818. virtual void InitMac (void);
  1819.  
  1820. Override this method and call inherited::InitMac (at the beginning of your
  1821. method) if your dragon requires more than the usual initializations.
  1822.  
  1823. InitMac initializes the usual system software managers.  Dragon::InitMac
  1824. calls InitGraf, InitFonts, InitWindows, InitMenus, TEInit, InitDialogs, and
  1825. InitCursor (in that order).
  1826.  
  1827. InitMem
  1828.  
  1829. virtual void InitMem (void);
  1830.  
  1831. Override this method if you want to increase the amount of memory allotted
  1832. to your dragon’s stack
  1833.  
  1834. InitMem enlarges your dragon’s application zone to its maximum size and
  1835. calls CallMoreMasters.
  1836.  
  1837. InitMilieu
  1838.  
  1839. virtual void InitMilieu (void);
  1840.  
  1841. Do not override this method — add to the ‘GChk’ resource instead
  1842.  
  1843. InitMilieu checks your dragon’s run-time environment against the
  1844. specifications in the ‘GChk’ 128 resource (as described below), and calls
  1845. Abort with an appropriate error code if the run-time environment is not
  1846. sufficient to run your dragon.  Otherwise, it calls InitAppleEvents.
  1847.  
  1848. InitPrefs
  1849.  
  1850. virtual void InitPrefs (void);
  1851.  
  1852. Do not override
  1853.  
  1854. This method creates and initializes the preferences object, asks
  1855. FindPrefsFile to look for a preferences file, and (if one is found or
  1856. created) tells the preferences object to use that file.  If the preferences
  1857. file had to be created, then the appropriate preferences resources will be
  1858. copied to it from the dragon’s application file.  InitPrefs ends by calling
  1859. ReadPrefs to read in the preferences from the file’s resources.
  1860.  
  1861. InteractWithUser
  1862.  
  1863. virtual Boolean InteractWithUser (long timeOut);
  1864.  
  1865. Do not override
  1866.  
  1867. Your dragon should call this method if it needs to interact with the user
  1868. (by putting up a dialog, for example) while it’s processing documents. 
  1869. InteractWithUser calls the Toolbox routine AEInteractWithUser using an idle
  1870. function (CallWaitIdle, described below) that ensures that events will be
  1871. processed normally while idling.
  1872.  
  1873. The timeOut parameter is the number of ticks your dragon is willing to wait
  1874. for the user to bring the dragon to the foreground.  A reasonable value for
  1875. timeOut might fall between 600 and 7200 ticks (10 seconds and 2 minutes).
  1876.  
  1877. IsPrefsFile
  1878.  
  1879. virtual Boolean IsPrefsFile (FSSpec *fss);
  1880.  
  1881. Do not override
  1882.  
  1883. This method checks the file specified by fss to make sure it has the proper
  1884. creator and type to be your dragon’s preferences file.
  1885.  
  1886. Note:    IsPrefsFile does not test the validity of the file’s resources — that
  1887. responsibility falls to the VerifyResources method of your subclass of the
  1888. Preferences class, if you choose to make one.
  1889.  
  1890. MakeAEQObject
  1891.  
  1892. virtual AppleEventQueue *MakeAEQObject (void);
  1893.  
  1894. Override this method if you implement a subclass of AppleEventsQueue
  1895.  
  1896. MakeAEQObject creates, and returns a reference to, an instance of class
  1897. AppleEventsQueue(or of a subclass of AppleEventsQueue, if you override this
  1898. method).
  1899.  
  1900. MakePrefsFile
  1901.  
  1902. virtual Boolean MakePrefsFile (FSSpec *fss);
  1903.  
  1904. Do not override
  1905.  
  1906. This method creates a new preferences file, as specified by fss.  It does
  1907. not add any resources to the file.
  1908.  
  1909. MakePrefsObject
  1910.  
  1911. virtual Preferences  *MakePrefsObject (void);
  1912.  
  1913. Override this method if you implement a subclass of Preferences
  1914.  
  1915. MakePrefsObject creates, and returns a reference to, an instance of class
  1916. Preferences (or of a subclass of Preferences, if you override this method).
  1917.  
  1918. ProcessDirectory
  1919.  
  1920. virtual void ProcessDirectory (void);
  1921.  
  1922. Your dragon should override this method if it processes directories (folders
  1923. and volumes) themselves rather than their contents (files and other
  1924. directories).
  1925.  
  1926. ProcessDirectory will be executed only when —
  1927.  
  1928. ( filesOnly == FALSE
  1929.   && curDocIsDirectory      // it's a folder or disk
  1930.   && curDirDepth == dirDepthLimit
  1931.   && CanProcessDoc () )
  1932.  
  1933. Here are some examples of the functionality of dragons that would need to
  1934. override ProcessDirectory:
  1935.  
  1936.     • Show information about a disk [presumably more that what the Finder’s
  1937. “Get Info” gives you]
  1938.     • Scan a folder (or folders) for new files dropped in it (or them), then
  1939. call ProcessFile for each such file (for example, to monitor incoming mail
  1940. or expand files [this is essentially what DownLine does]
  1941.     • Copy the full paths of selected directories (and files) to the clipboard
  1942. [this is what FilePaths does]
  1943.  
  1944. ProcessDoc
  1945.  
  1946. virtual void ProcessDoc (void);
  1947.  
  1948. Don’t override
  1949.  
  1950. This method (which should normally not be overridden) is the “bottleneck”
  1951. through which all documents must pass before they can be processed.  It
  1952. begins by checking to see that the document specified by curDocFSS and
  1953. curDocPB (both of which are valid at this point) is of a kind that could be
  1954. drag-and-dropped on your dragon, then applies any special filtering that you
  1955. may have set up in CustomFilterDoc.  If the document meets those
  1956. requirements, ProcessDoc passes it as follows:
  1957.  
  1958.     • If the document is a file belonging to your dragon (curDocIsFile &&
  1959. curDocCreator == this->signature), then it’s passed to ProcessOwnedFile.
  1960.     • If the document is a file that does not belong to your dragon, then it’s
  1961. passed to ProcessFile — this is the usual case.
  1962.     • If the document is a folder or volume and the maximum level of folder
  1963. opening (see the descriptions of curDirDepthLimit and dirDepthLimit in the
  1964. Instance Variables section) has not yet been reached, then it’s passed to
  1965. ProcessDocsInDirectory, which will process the documents inside the folder
  1966. (or volume).
  1967.     • If the document is a folder or volume at the maximum level of folder
  1968. opening, and if your dragon sets filesOnly = FALSE, then it will be passed
  1969. to ProcessDirectory.
  1970.  
  1971. ProcessDocsInDirectory
  1972.  
  1973. virtual void ProcessDocsInDirectory (short vRefNum, long dirID);
  1974.  
  1975. Don’t override
  1976.  
  1977. This method looks through the current directory and, for each thing it finds
  1978. there, sets up curDocFSS and curDocPB and calls ProcessDoc.
  1979.  
  1980. ProcessDroppings
  1981.  
  1982. virtual OSErr ProcessDroppings (AEDescList *docList);
  1983.  
  1984. ProcessDroppings loops through the documents that were drag-and-dropped on
  1985. your application and calls ProcessDoc for each one after setting up
  1986. curDocFSS and curDocPB.  Alias files are resolved here (if resolveAliases !=
  1987. FALSE).  ProcessDroppings calls BeginProcessing before handling the first
  1988. document and EndProcessing after the last.
  1989.  
  1990. ProcessFile
  1991.  
  1992. virtual void ProcessFile (void);
  1993.  
  1994. Override except in unusual cases
  1995.  
  1996. ProcessFile is the heart of any typical sub-class of Dragon.  Unless your
  1997. dragon only handles volumes or folders, you will certainly need to override
  1998. this method — this is where the actual work is done (or the methods that do
  1999. the work are called).
  2000.  
  2001. ProcessOwnedFile
  2002.  
  2003. virtual void ProcessOwnedFile (void);
  2004.  
  2005. Override if your dragon creates any special file types (other than
  2006. preferences files) and treats them differently than it does files which it
  2007. didn’t create
  2008.  
  2009. The default behavior for ProcessOwnedFile is to check if the file designated
  2010. by curDocFSS and curDocPB is a preferences file and, if it is, to use the
  2011. preferences found in it.
  2012.  
  2013. ReadPrefs
  2014.  
  2015. virtual void ReadPrefs (void);
  2016.  
  2017. Call inherited::ReadPrefs if you override this method
  2018.  
  2019. The purpose of this method is to read in settings from the dragon’s
  2020. preferences file (from the resources specified in its ‘PrRo’ 128 resource —
  2021. see description below) and change the appropriate instance variables
  2022. accordingly.  It should call preferences->GetPrefResource for each
  2023. preferences resource.  The Dragon::ReadPrefs method sets the following
  2024. instance variables:
  2025.  
  2026.     filesOnly            sleepValue[0..3]    resolveAliases    sleepTime
  2027.     followAliasChain    dirDepthLimit        autoQuit
  2028.  
  2029. You should check to see if preferences->GetPrefResource returns NULL when
  2030. overriding this method, and in any other method that might rely on a
  2031. preferences resource being in memory — an incomplete preferences file should
  2032. never cause a crash.  See the code in the How do I… section above for an
  2033. example.
  2034.  
  2035. Note:    Remember that your dragon’s preferences will come from the application
  2036. file if no preferences file could be found or created.
  2037.  
  2038. ResumeAEvent
  2039.  
  2040. virtual void ResumeAEvent (void);
  2041.  
  2042. Do not override
  2043.  
  2044. This method is called by Run whenever WaitNextEvent doesn’t report an event
  2045. and one or more previously received Apple events are pending.  ResumeAEvent
  2046. asks the aeQueue object for the oldest pending Apple event, then calls
  2047. AEResumeTheCurrentEvent to handle the event normally.
  2048.  
  2049. Run
  2050.  
  2051. virtual void Run (void);
  2052.  
  2053. Do not override
  2054.  
  2055. Run contains the main event loop, which calls either DoEvent, DoIdle, or (if
  2056. there are any pending Apple events) ResumeAEvent.  The loop terminates only
  2057. when this->running is set to FALSE (by StopRunning).
  2058.  
  2059. SaveDocInfo
  2060.  
  2061. virtual void SaveDocInfo (Boolean refreshFinder);
  2062.  
  2063. Call SaveDocInfo right after you change one or more of the following values:
  2064.  
  2065. curFileType    curFileCreator    curFileFlags
  2066.  
  2067. curDocCreated    curDocModified
  2068.  
  2069. or any other field in *curDocPB that PBSetCatInfo takes as input.
  2070.  
  2071. Note:    To rename the current document, you should call FSpRename (rather than
  2072. just changing *curDocName) after calling SaveDocInfo (TRUE).
  2073.  
  2074. Warning:    If your dragon makes any low-level File Manager calls that leave
  2075. garbage in any fields in *curDocPB that PBSetCatInfo takes as input, then it
  2076. should do so after calling this method, or save and restore those values, or
  2077. refrain from calling SaveDocInfo at all.  Table 2 contains a partial list of
  2078. low-level File Manager calls that leave garbage in fields that PBSetCatInfo
  2079. uses.
  2080.  
  2081.     <Table 2 omitted>
  2082.  
  2083. SetUpMenus
  2084.  
  2085. virtual void SetUpMenus (void);
  2086.  
  2087. If you override this method, call inherited::SetUpMenus at the beginning of
  2088. your method and DrawMenuBar at the end
  2089.  
  2090. SetUpMenus is called by Start (unless autoQuit != FALSE).  It initializes
  2091. your dragon’s menus, including (by default) a standard Apple Menu, a File
  2092. menu with just one item (Quit), and an Edit menu with the five basic editing
  2093. commands (Undo, Cut, Copy, Paste, and Clear).
  2094.  
  2095. ShowProgress
  2096.  
  2097. virtual void ShowProgress (void);
  2098.  
  2099. For future compatibility, you should call inherited::DoBusy if you override
  2100. this method
  2101.  
  2102. Override ShowProgress if you want your dragon to give the user some visual
  2103. indication of the progress it’s making on processing the documents the user
  2104. drag-and-dropped on it.  If your dragon doesn’t look inside directories
  2105. (i.e., if dirDepthLimit == 0) then you might want to show a progress bar
  2106. similar to the one the Finder puts up while copying files.  If it does look
  2107. in directories, then you could display the name of each document as it’s
  2108. processed.
  2109.  
  2110. Warning:    ShowProgress is called for every file, folder, or disk
  2111. drag-and-dropped on your dragon (or sent in an Open Documents event from a
  2112. source other than the Finder) — even ones that your dragon can’t (for
  2113. whatever reason) process.  Keep this mind if you want to display the names
  2114. only of documents as they’re processed — you’ll need to override
  2115. ProcessFile, ProcessDirectory, or ProcessDocsInDirectory (or some
  2116. combination of those three) instead.
  2117.  
  2118.     Also, your DoBusy method should not change *curDocFSS or *curDocPB in any
  2119. way.
  2120.  
  2121. Note:    Implementing a movable modal window (as an instance of a class that
  2122. you can override) is high on the list of future plans for Dragonsmith, but
  2123. adding it to Dragon will probably require significant changes to ProcessDoc
  2124. and ShowProgress.  If you override either of these methods, keep in mind
  2125. that your code may have to be changed later for compatibility with new
  2126. releases of Dragonsmith.
  2127.  
  2128. Start
  2129.  
  2130. virtual void Start (void);
  2131.  
  2132. Start initializes your dragon’s run-time environment — memory, menus,
  2133. preferences, events, etc.
  2134.  
  2135. StopProcessing
  2136.  
  2137. virtual void StopProcessing (OSErr err);
  2138.  
  2139. Call inherited::StopProcessing if you override this method
  2140.  
  2141. StopProcessing should be called whenever an error occurs that is serious
  2142. enough that processing should be stopped (including cancellation by the
  2143. user).  The parameter should specify the reason for stopping. 
  2144. Dragon::StopProcessing just sets abortProcessing = TRUE; your Dragon
  2145. subclass can display an error message or otherwise indicate that something
  2146. went wrong (but it should stop “quietly” if the user generated a cancel
  2147. event).
  2148.  
  2149. StopRunning
  2150.  
  2151. virtual void StopRunning (void);
  2152.  
  2153. This method sets running = FALSE, after calling StopProcessing if your
  2154. dragon is currently processing an Open Documents event.  The dragon’s main
  2155. event loop will terminate as soon as control is returned to Run.
  2156.  
  2157. SuspendAEvent
  2158.  
  2159. virtual OSErr SuspendAEvent (AppleEvent *event, AppleEvent *reply,
  2160. AEHandlerFunc *handler, long refcon);
  2161.  
  2162. Do not override
  2163.  
  2164. SuspendAEvent is called by ProcessOdoc any time your dragon receives an Open
  2165. Documents event while processing a previously received one.  SuspendAEvent
  2166. asks the aeQueue object to add the event to its queue, then calls the
  2167. Toolbox routine AESuspendTheCurrentEvent to let the System know the event
  2168. isn’t being handled.
  2169.  
  2170. Warning:    Be very careful if you decide to override this method.  Any
  2171. application that receives an Apple event while processing one received
  2172. earlier must either call AESuspendTheCurrentEvent or interrupt the first
  2173. event until handling of the second is completed.  It appears that dividing
  2174. CPU time between the handling of several Apple events (without calling
  2175. AESuspendTheCurrentEvent and AEResumeTheCurrentEvent at the appropriate
  2176. times) will cause the system to grow very confused!
  2177.  
  2178. WaitIdle
  2179.  
  2180. virtual Boolean WaitIdle (EventRecord *theEvent, long *sleep,
  2181. RgnHandle *mouseRgn);
  2182.  
  2183. WaitIdle will be called whenever your dragon gets an update, activate, null,
  2184. or OS event while it’s waiting for AEInteractWithUser to return — i.e.,
  2185. while it waits for the user to bring it to the foreground.  The default
  2186. behavior in the Dragon class is to let the main event handler, DoEvent, pass
  2187. the buck.  Please note that recursion is not a possibility unless you do
  2188. some very strange overriding of the DoActivate, DoUpdateEvent, DoOSEvent,
  2189. DoSuspend, or DoResume methods.
  2190.  
  2191.  
  2192. ------------------------------------------------------
  2193. RESOURCES
  2194. ------------------------------------------------------
  2195.  
  2196. This section briefly describes all of the resources that should be present
  2197. in your dragon’s project resource file (with the exception of the ‘SIZE’ and
  2198. signature resources, which THINK C will add to the built application).  All
  2199. of the project resource files provided with Dragonsmith 1.1 contain these
  2200. resources.  The best way to gain a full understanding of the
  2201. Dragonsmith-specific resources is to view them in ResEdit and look for
  2202. mentions of them in the Dragonsmith source code.
  2203.  
  2204. Dragonsmith resources
  2205.  
  2206. The following resources have Dragonsmith-specific functions:
  2207.  
  2208. ALRT 129        Alert used by Dragon::Error.
  2209.  
  2210. DITL 129        Dialog item list for use with ‘ALRT’ 129.
  2211.  
  2212. DrPr 128        Dragon class preferences.  The following Dragon instance variables
  2213. are all copied from values in this resource:
  2214.         autoQuit            resolveAliases    followAliasChain
  2215.         sleepValue[0..3]    filesOnly        dirDepthLim
  2216. If your dragon sets any of these instance variables in its constructor, then
  2217. you should put the same values into the fields in your project resource
  2218. file’s ‘DrPr’ 128 resource.  Forgetting to do so can cause tremendous
  2219. frustration.
  2220.  
  2221. GChk 128        A list of Gestalt calls and the values that they should return.  InitMilieu
  2222. passes this resource to the GestaltBatchCheck function, which returns noErr if the
  2223. run-time environment is sufficient for the dragon to function properly.  Each entry
  2224. in the list has the following structure:
  2225.     typedef struct {
  2226.         OSType  selector;      // Selector to call Gestalt with
  2227.         short   compOp;        // Type of comparison to make
  2228.         short   failureError;  // Error to return if check fails
  2229.         long    compValue;     // Check Gestalt result against this
  2230.     }
  2231. Possible values for the compOp field are listed in the file GestaltUtils.h.
  2232.  
  2233. MENU 128        Apple menu,
  2234.     129        File menu,
  2235.     130        Edit menu.
  2236.  
  2237. MoMa 128        Number of times to call MoreMasters.
  2238.  
  2239. PrRo 128        Preferences roster — a list of the dragon’s preferences resources. 
  2240. You must add to this list whenever you add a new preferences resource.
  2241.  
  2242. STR 128        Name of the dragon’s preferences file.  To prevent a preferences
  2243. file from being created, put a null string in this resource and delete the
  2244. ‘FREF’ resource for the type designated by the instance variable
  2245. prefsFileType.
  2246.  
  2247. ResEdit templates for the Dragonsmith-specific resources are available in
  2248. the ‘Dragonsmith TMPLs’ file — keep this file open whenever viewing or
  2249. editing them.
  2250.  
  2251. Finder-related resources
  2252.  
  2253. The following resoures are used by the Finder to correctly launch an
  2254. application, control drag-and-drop onto it, and display its icons and
  2255. information in the Finder:
  2256.  
  2257. <signature> 0    The type of this resource should be the same as your
  2258. application’s signature (set via the ‘Set Project Type…’ dialog in THINK C).
  2259.  It contains a copyright string for the application.
  2260.  
  2261. BNDL 128        This resource coordinates an application’s Finder-related
  2262. resources.  You can ResEdit 2.1’s ‘BNDL’ editor to modify this resource as
  2263. well as the ‘FREF’, signature, and icon resources.
  2264.  
  2265. FREF 128, etc.    These resources designate the types of files your dragon can
  2266. process.  Make sure you have one for every document type your dragon is
  2267. capable of processing, plus one (‘APPL’) for the application itself, plus
  2268. one for the file type designated by the instance variable prefsFileType
  2269. (normally ‘pref’) if your dragon creates a preferences file.
  2270.  
  2271. Use the values ‘fold’ and ‘disk’ to allow drag-and-drop of folders and
  2272. volumes (respectively) onto your dragon.
  2273.  
  2274. Use the value ‘****’ to specify that your dragon can process files (not
  2275. folders or volumes) of any type.
  2276.  
  2277. hfdr
  2278. styl
  2279. TEXT 128        These three resources in combination provide Ballon Help for your
  2280. dragon’s icon in the Finder.  Delete all three if you don’t want this
  2281. feature.
  2282.  
  2283. icl4,
  2284. icl8,
  2285. ICN#,
  2286. ics#,
  2287. ics4,
  2288. ics8            Icons for your dragon’s application and files.
  2289.  
  2290. SIZE –1        The SIZE resource must be set up correctly for an application to
  2291. accept Apple events, and the Dragon class relies on Apple events — if a
  2292. dragon can’t get an Open Documents event, it won’t do anything.  Don’t put
  2293. your own ‘SIZE’ resource in the .rsrc file — use the SIZE settings available
  2294. by choosing ‘Set Project Type…’ from THINK C’s Project menu.
  2295.  
  2296. vers 1        This is the ‘true’ version string which appears in the Get Info…
  2297. window
  2298.  
  2299. vers 2        This string appears directly under your application’s name in its Get
  2300. Info… window in the Finder.  The dragons provided with Dragonsmith use the
  2301. words ‘a Dragon sub-species’ in this string, but you’re not required to
  2302. follow this convention in your own dragons.
  2303.  
  2304. Inside Macintosh, Volume VI has an extensive description of Finder-related
  2305. resources on pages 9-5 to 9-24 and 9-34 to 9-35 — read it for more
  2306. information on these resources.  Keep in mind that many of these resources
  2307. must be modified before your dragon’s first built version, or you may have
  2308. to rebuild the desktop to make the Finder’s behavior reflect any changes in
  2309. them.
  2310.  
  2311.  
  2312.